﻿//-----------------------------------------------------------------------
// <copyright file="MLVBNetCodeTemplate.cs" company="MAPILab Ltd">
//     Copyright (c) MAPILab Ltd.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace MAPILab.SharePoint.Explorer.CodeForm.CodeTemplates
{
    using System;
    using System.Collections.Generic;
    using System.Reflection;
    using System.Text;
    using MAPILab.SharePoint.Explorer.Properties;
    using MAPILab.SharePoint.Explorer.Utilities;
    
    /// <summary>
    /// VB.Net code template class
    /// </summary>
    class MLVBNetCodeTemplate : MLBaseCodeTemplate
    {     
        #region Methods

        /// <summary>
        /// Code template on VB.Net
        /// </summary>
        /// <returns>string that contains code template</returns>
        public override string GenerateTemplate()
        {
            StringBuilder template = new StringBuilder();

            foreach (string nameSpaceName in Settings.Default.namespaces)
            {
                template.Append("Imports " + nameSpaceName + "\r\n");
            }

            template.Append("\r\n");

            template.Append("Public Class Tester" + "\r\n");
            
            template.Append("\tShared Sub Main(");

            AddMainParameters(template);

            template.Append(")");

            GenerateMethodsCallTemplate(template);

            template.Append("\n\t\t");
            
            //add template for output browser
            GenerateOutput(template);

            template.Append("\n\tEnd Sub\r\n");
            template.Append("End Class\r\n");

            return template.ToString();
        }

        /// <summary>
        /// Generate template for output
        /// </summary>
        /// <param name="template">string that contains code</param>
        protected override void GenerateOutput(StringBuilder template)
        {
            template.Append("\n\t\t");
            template.Append("\n\t\t' Output browser configuration");
            template.Append("\n\t\t'browser.Text = \"Browser window\"");
            template.Append("\n\t\t'browser.DisplayMode = MAPILab.SharePoint.Explorer.Utilities.ScriptRunner.DisplayMode.Expanded");
            template.Append("\n\t\t'browser.OpenInNewWindow = False");
            template.Append("\n\t\tbrowser.ReturnValue = Nothing");
        }

        /// <summary>
        /// Add current method
        /// </summary>
        /// <param name="template">output template</param>
        /// <param name="methParam">method parameter to add</param>
        protected override void GenerateMethodCallTemplate(StringBuilder template, MLMethodParameter methParam)
        {
            MethodInfo methodInfo = methParam.MethodInfo;
            ParameterInfo[] parameters = methodInfo.GetParameters();

            template.AppendFormat("\n\t\t' Calling method {0}\r\n", methodInfo.Name);

            //Adding parameters for method
            List<ParameterNameAndType> paramList = AddMethodParameters(template, parameters);

            foreach (ParameterNameAndType paramNameAndType in paramList)
            {
                template.AppendFormat("\t\tDim {0} As {1}{2}\r", paramNameAndType.Name, paramNameAndType.TypeName, (paramNameAndType.IsOutParameter ? "" : " = "));
            }

            bool nonVoidIndent = false;

            if (!(methodInfo.ReturnType == typeof(void)))
            {
                template.AppendFormat("\t\tDim {0} As {1} = ", string.Format("value{0}", methodsParamCounter++), MLUtils.GetTypeOutput(MLUtils.GetType(methodInfo.ReturnType)));
                nonVoidIndent = true;
            }
            else
            {
                template.Append("\t\t");
            }

            if (methodInfo.IsPublic)
            {
                //Add Public Method
                AddPublicMethod(template, methParam, methodInfo, paramList, nonVoidIndent);
            }
            else
            {
                //Add Non Public Method
                AddNonPublicMethod(template, methParam, methodInfo, paramList, nonVoidIndent);
            }

            template.Append("\t\t\r");
        }

        /// <summary>
        /// Add non public method
        /// </summary>
        /// <param name="template">output template</param>
        /// <param name="methParam">method parameter to add</param>
        /// <param name="methodInfo">adding method</param>
        /// <param name="paramList">parameters list</param>
        /// <param name="nonVoidIndent">non void indent</param>
        protected override void AddNonPublicMethod(StringBuilder template, MLMethodParameter methParam, MethodInfo methodInfo, List<ParameterNameAndType> paramList, bool nonVoidIndent)
        {
            string objectName = String.Empty;

            if (!(methodInfo.IsStatic))
            {
                objectName = methParam.MainParamName;
            }
            else
            {
                objectName = "Nothing";
            }

            if (nonVoidIndent)
            {
                template.Append("DirectCast(");
            }

            template.AppendFormat("{0}.Invoke({1}, ", methParam.MainParamName.Replace("mo_", ""), objectName);

            if (paramList.Count > 0)
            {
                template.Append("New Object(){");
                GetParameters(template, paramList, nonVoidIndent, true);
                template.Append("}");
            }
            else
            {
                template.Append("Nothing");
            }

            if (nonVoidIndent)
            {
                template.Append(", " + MLUtils.GetTypeOutput(MLUtils.GetType(methodInfo.ReturnType)) + ")");
            }

            template.Append("\r\n");
        }
        
        /// <summary>
        /// Add public method
        /// </summary>
        /// <param name="template">output template</param>
        /// <param name="methParam">method parameter to add</param>
        /// <param name="methodInfo">adding method</param>
        /// <param name="paramList">parameters list</param>
        /// <param name="nonVoidIndent">non void indent</param>
        protected override void AddPublicMethod(StringBuilder template, MLMethodParameter methParam, MethodInfo methodInfo, List<ParameterNameAndType> paramList, bool nonVoidIndent)
        {
            string paramName = String.Empty;

            if (!(methodInfo.IsStatic))
            {
                paramName = methParam.MainParamName;
            }
            else
            {
                paramName = MLUtils.GetTypeOutput(methParam.ObjectValue.GetType());
            }

            template.AppendFormat("{0}.{1}(", paramName, methodInfo.Name);

            GetParameters(template, paramList, nonVoidIndent, false);
            
            if (nonVoidIndent)
            {
                template.Append(")");
            }

            template.Append("\r\n");
        }

        /// <summary>
        /// Add parametrs for method
        /// </summary>
        /// <param name="template">code template</param>
        /// <param name="paramList">list of parameters</param>
        /// <param name="nonVoidIndent">non void indent</param>
        /// <param name="IsInvoke">It is for invoke or not</param>
        protected override void GetParameters(StringBuilder template, List<ParameterNameAndType> paramList, bool nonVoidIndent, bool IsInvoke)
        {
            if (paramList.Count > 0)
            {
                int count = 0;

                foreach (ParameterNameAndType paramNameAndType in paramList)
                {
                    if (count > 0)
                    {
                        template.AppendFormat(", ");
                    }

                    template.Append(paramNameAndType.Name);

                    count++;
                }
            }
        }

        /// <summary>
        /// Add parameter to Main method on VB.Net
        /// </summary>
        /// <param name="template">output template</param>
        /// <param name="firstParam">is first parameter or not</param>
        /// <param name="paramName">Parameter name</param>
        /// <param name="paramValue">Parameter value</param>
        protected override void AddMainParameter(StringBuilder template, ref bool firstParam, string paramName, object paramValue)
        {
            if (firstParam)
            {
                firstParam = false;
            }
            else
            {
                template.Append(", ");
            }

            Type paramType = MLUtils.GetType(paramValue.GetType());

            if (paramValue is MethodInfo)
            {
                paramType = MLUtils.GetType(typeof(MethodInfo));
            }

            mainParams.Add(paramValue);
            
            //add reference for type
            AddTypeReferences(paramValue.GetType());

            template.Append("ByVal " + paramName + " As " + MLUtils.GetTypeOutput(paramType));
        }

        #endregion
    }
}
